﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AlphaD.Core
{
    public class LinearDiffEq2DiscontBvp
    {
        #region Constructors

        public LinearDiffEq2DiscontBvp(
            BoundaryCondition leftCondition, 
            BoundaryCondition rightCondition,
            double[] disconts,
            double[] k,
            double[] r,
            double[] f,
            double[] alpha)
        {
            #region Validation Input Params

            if (leftCondition.X < rightCondition.X == false)
            {
                throw new ArgumentException("The condition must take a place: a < b");
            }

            this.EnsureDiscontsValid(leftCondition.X, rightCondition.X, disconts);
            this.EnsureKValid(disconts.Length, k);
            this.EnsureRValid(disconts.Length, r);
            this.EnsureFValid(disconts.Length, f);
            this.EnsureAlphaValid(disconts.Length, alpha);

            #endregion Validation Input Params

            this.LeftCondition = leftCondition;
            this.RightCondition = rightCondition;
            this.Disconts = Array.AsReadOnly(disconts);
            this.K = Array.AsReadOnly(k);
            this.R = Array.AsReadOnly(r);
            this.F = Array.AsReadOnly(f);
            this.Alpha = Array.AsReadOnly(alpha);

        }

        #endregion Constructors


        #region Public Properties

        public ReadOnlyCollection<double> Disconts { get; private set; }
        public ReadOnlyCollection<double> K { get; private set; }
        public ReadOnlyCollection<double> R { get; private set; }
        public ReadOnlyCollection<double> F { get; private set; }
        public ReadOnlyCollection<double> Alpha { get; private set; }
        public BoundaryCondition LeftCondition { get; private set; }
        public BoundaryCondition RightCondition { get; private set; }

        #endregion Public Properties

        #region Validatioin
        private void EnsureDiscontsValid(double a, double b, double[] disconts)
        {
            if (disconts.Length > 0 == false)
            {
                throw new ArgumentException("The condition must take a place: disconts.Length > 0");
            }

            if (a < disconts[0] == false)
            {
                throw new ArgumentException("The condition must take a place: a < discont[0]");
            }
            for(int i = 0; i < disconts.Length - 1; i++)
            {
                if (disconts[i] < disconts[i + 1] == false)
                {
                    throw new ArgumentException("The condition must take a place: disconts[i] < disconts[i + 1]");
                }
            }
            if (disconts[disconts.Length - 1] < b == false)
            {
                throw new ArgumentException("The condition must take a place: disconts[disconts.Length - 1] < b");
            }
        }

        private void EnsureKValid(int n, double[] k)
        {
            if (k.All(a => a > 0) == false)
            {
                throw new ArgumentException("The condition must take a place: k(x) > 0");
            }
            if ((n + 1 == k.Length) == false)
            {
                throw new ArgumentException("The condition must take a place: discontCount == ks.Length + 1");
            }
        }

        private void EnsureRValid(int n, double[] r)
        {
            if (r.All(a => a > 0) == false)
            {
                throw new ArgumentException("The condition must take a place: r(x) > 0");
            }
            if ((n + 1 == r.Length) == false)
            {
                throw new ArgumentException("The condition must take a place: discontCount == r.Length + 1");
            }
        }

        private void EnsureFValid(int n, double[] f)
        {
            if ((n + 1 == f.Length) == false)
            {
                throw new ArgumentException("The condition must take a place: discontCount == f.Length + 1");
            }
        }

        private void EnsureAlphaValid(int n, double[] alpha)
        {
            if ((n == alpha.Length) == false)
            {
                throw new ArgumentException("The condition must take a place: discontCount == alpha.Length");
            }
        }

        #endregion Validatioin
    }
}
